package com.zhehekeji.opsys.api.plugin.wechat.service;

import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.zhehekeji.opsys.api.cache.WechatCache;
import com.zhehekeji.opsys.api.common.util.DateFormatUtil;
import com.zhehekeji.opsys.api.entity.TWechatConfig;
import com.zhehekeji.opsys.api.entity.TWechatRedpackRecord;
import com.zhehekeji.opsys.api.entity.TWechatToken;
import com.zhehekeji.opsys.api.plugin.wechat.code.WechatResultCode;
import com.zhehekeji.opsys.api.plugin.wechat.enm.MsgType;
import com.zhehekeji.opsys.api.plugin.wechat.rsp.CheckSignCustomRsp;
import com.zhehekeji.opsys.api.plugin.wechat.rsp.QrcodeCreateRsp;
import com.zhehekeji.opsys.api.plugin.wechat.rsp.QrcodeShowRsp;
import com.zhehekeji.opsys.api.plugin.wechat.rsp.RedpackRsp;
import com.zhehekeji.opsys.api.plugin.wechat.rsp.TextRsp;
import com.zhehekeji.opsys.api.plugin.wechat.util.DESedeUtils;
import com.zhehekeji.opsys.api.plugin.wechat.util.FileUtils;
import com.zhehekeji.opsys.api.plugin.wechat.util.HttpUtils;
import com.zhehekeji.opsys.api.plugin.wechat.util.XmlUtils;
import com.zhehekeji.opsys.api.service.CommonService;
import com.zhehekeji.opsys.api.util.UUIDUtils;

import net.sf.json.JSONObject;

/**
 * @ClassName WechatCustomManagerService
 * @Description TODO
 * @author chenweiliu chenwei.liu@163.com
 * @date 2018-2-1   下午1:42:32
 */
@Service
public class WechatCustomManagerService extends CommonService{
	
	private static final Logger logger = LoggerFactory.getLogger(WechatCustomManagerService.class);
	@Autowired
	private WechatCache wechatCache;
	@Autowired
	private WechatManagerService wechatManagerService;
	
	public QrcodeShowRsp getQrcodeShow(String activityCode, String userID, int amount, int limitTimes, int limitCycle) {
		QrcodeShowRsp rsp = new QrcodeShowRsp();
		String resultDesc = "获取二维码成功！";
		if (StringUtils.isBlank(activityCode)){
			resultDesc = "获取二维码失败，活动编码非法！";
			logger.error(resultDesc);
			rsp.setResultCode(WechatResultCode.PARAMETER_IS_NOT_LEGAL);
			rsp.setResultDesc(resultDesc);
			return rsp;
		}
		if (StringUtils.isBlank(userID)){
			resultDesc = "获取二维码失败，用户账号非法！";
			logger.error(resultDesc);
			rsp.setResultCode(WechatResultCode.PARAMETER_IS_NOT_LEGAL);
			rsp.setResultDesc(resultDesc);
			return rsp;
		}
		if (amount <= 0 || amount > 20000){
			resultDesc = "获取二维码失败，金额已超范围(0,20000]！";
			logger.error(resultDesc);
			rsp.setResultCode(WechatResultCode.PARAMETER_IS_NOT_LEGAL);
			rsp.setResultDesc(resultDesc);
			return rsp;
		}
		if (limitTimes < 0){
			limitTimes = 0;
		}
		if (limitCycle < 0){
			limitCycle = 0;
		}
		try{
			TWechatConfig tmpTWechatConfig = checkWechatConfig(rsp);
			if (rsp.getResultCode() != WechatResultCode.SUCCESS){
				return rsp;
			}
			TWechatToken tmpTWechatToken = checkWechatToken(rsp);
			if (rsp.getResultCode() != WechatResultCode.SUCCESS){
				return rsp;
			}
			String scene = activityCode + "$" + userID + "$" + amount + "$" + limitTimes + "$" + limitCycle;
			getWechaturl(scene, tmpTWechatConfig, tmpTWechatToken, rsp);
			if (rsp.getResultCode() != WechatResultCode.SUCCESS){
				return rsp;
			}
			logger.info(resultDesc);
		}catch (Exception e){
			resultDesc = "获取二维码失败，程序异常！";
			logger.error(resultDesc, e);
			rsp.setResultCode(WechatResultCode.APPLICATION_EXCEPTION);
			rsp.setResultDesc(resultDesc);
		}
		return rsp;
	}

	public QrcodeShowRsp getSafeQrcodeShow(String sign) {
		QrcodeShowRsp rsp = new QrcodeShowRsp();
		String resultDesc = "获取二维码成功！";
		try{
			CheckSignCustomRsp tmpCheckSignCustomRsp = checkSign(sign);
			boolean checkFlag = tmpCheckSignCustomRsp.isFlag();
			if (!checkFlag){
				rsp.setResultCode(WechatResultCode.PARAMETER_IS_NOT_LEGAL);
				rsp.setResultDesc("获取二维码失败，签名非法！");
				return rsp;
			}
			TWechatConfig tmpTWechatConfig = checkWechatConfig(rsp);
			if (rsp.getResultCode() != WechatResultCode.SUCCESS){
				return rsp;
			}
			TWechatToken tmpTWechatToken = checkWechatToken(rsp);
			if (rsp.getResultCode() != WechatResultCode.SUCCESS){
				return rsp;
			}
			getWechaturl(sign, tmpTWechatConfig, tmpTWechatToken, rsp);
			if (rsp.getResultCode() != WechatResultCode.SUCCESS){
				return rsp;
			}
			logger.info(resultDesc);
		}catch (Exception e){
			resultDesc = "获取二维码失败，程序异常！";
			logger.error(resultDesc, e);
			rsp.setResultCode(WechatResultCode.APPLICATION_EXCEPTION);
			rsp.setResultDesc(resultDesc);
		}
		return rsp;
	}
	
	private TWechatConfig checkWechatConfig(QrcodeShowRsp rsp) throws SQLException{
		TWechatConfig tmpTWechatConfig = wechatCache.getWechatConfig();
		String resultDesc = "获取二维码成功！";
		if (tmpTWechatConfig == null){
			resultDesc = "获取二维码失败，微信配置不存在！";
			logger.error(resultDesc);
			rsp.setResultCode(WechatResultCode.WECHAT_CONFIG_DOES_NOT_EXIST);
			rsp.setResultDesc(resultDesc);
			return tmpTWechatConfig;
		}
		String tmpQrcodeCreateUrl = tmpTWechatConfig.getQrcodeCreateUrl();
		if (StringUtils.isBlank(tmpQrcodeCreateUrl)){
			resultDesc = "获取二维码失败，二维码生成调用Url为空！";
			logger.error(resultDesc);	
			rsp.setResultCode(WechatResultCode.QRCODE_CREATE_URL_DOES_NOT_EXIST);
			rsp.setResultDesc(resultDesc);
			return tmpTWechatConfig;
		}
		String tmpQrcodeShowUrl = tmpTWechatConfig.getQrcodeShowUrl();
		if (StringUtils.isBlank(tmpQrcodeShowUrl)){
			resultDesc = "获取二维码失败，二维码生成呈现Url为空！";
			logger.error(resultDesc);	
			rsp.setResultCode(WechatResultCode.QRCODE_SHOW_URL_DOES_NOT_EXIST);
			rsp.setResultDesc(resultDesc);
			return tmpTWechatConfig;
		}
		String tmpQrcodePicStoreDir = tmpTWechatConfig.getQrcodePicStoreDir();
		if (StringUtils.isBlank(tmpQrcodePicStoreDir)){
			resultDesc = "获取二维码失败，图片存储路径不存在！";
			logger.error(resultDesc);
			rsp.setResultCode(WechatResultCode.QRCODE_STORE_DIR_DOES_NOT_EXIST);
			rsp.setResultDesc(resultDesc);
			return tmpTWechatConfig;
		}
		String tmpQrcodePicHttpPath = tmpTWechatConfig.getQrcodePicHttpPath();
		if (StringUtils.isBlank(tmpQrcodePicHttpPath)){
			resultDesc = "获取二维码失败，图片访问路径不存在！";
			logger.error(resultDesc);
			rsp.setResultCode(WechatResultCode.QRCODE_HTTP_PATH_DOES_NOT_EXIST);
			rsp.setResultDesc(resultDesc);
			return tmpTWechatConfig;
		}
		return tmpTWechatConfig;
	}
	
	private TWechatToken checkWechatToken(QrcodeShowRsp rsp) throws SQLException{
		TWechatToken tmpTWechatToken = entityDao.get(TWechatToken.class, null, null);
		if (tmpTWechatToken == null || StringUtils.isBlank(tmpTWechatToken.getAccessToken())){
			logger.error("获取二维码失败，访问令牌不存在！");
			rsp.setResultCode(WechatResultCode.ACCESS_TOKEN_DOES_NOT_EXIST);
			rsp.setResultDesc("获取二维码失败，访问令牌不存在！");
		}
		return tmpTWechatToken;
	}
	
	public CheckSignCustomRsp checkSign(String sign) throws SQLException{
		CheckSignCustomRsp rsp = new CheckSignCustomRsp();
		rsp.setFlag(true);
		if (StringUtils.isBlank(sign)){
			logger.error("签名非法！");
			rsp.setFlag(false);
			return rsp;
		}
		TWechatConfig tmpTWechatConfig = wechatCache.getWechatConfig();
		if (tmpTWechatConfig == null){
			logger.error("微信配置不存在！");
			rsp.setFlag(false);
			return rsp;
		}
		String tmpQrcodePicSignKey = tmpTWechatConfig.getQrcodePicSignKey();
		if (StringUtils.isBlank(tmpQrcodePicSignKey)){
			logger.error("二维码签名key不存在！");	
			rsp.setFlag(false);
			return rsp;
		}
		String tmpPlaintext;
		try{
			tmpPlaintext = DESedeUtils.decrypt(sign, tmpQrcodePicSignKey);
		}catch (Exception e){
			logger.error("签名非法！", e);
			rsp.setFlag(false);
			return rsp;
		}
		String[] tmpArrayDecrypt = tmpPlaintext.split("\\&");
		if (tmpArrayDecrypt.length != 7){
			logger.error("签名参数长度不等于7！");
			rsp.setFlag(false);
			return rsp;
		}
		String[] tmpArrayParam;
		Map<String, String> tmpMap = new HashMap<String, String>();
		for (String tmpStr : tmpArrayDecrypt){
			if (StringUtils.isBlank(tmpStr)){
				logger.error("签名参数不能为空！");
				rsp.setFlag(false);
				return rsp;
			}
			tmpArrayParam = tmpStr.split("=");
			if (tmpArrayParam == null || tmpArrayParam.length != 2){
				logger.error("签名参数不满足k=v格式");
				rsp.setFlag(false);
				return rsp;
			}
			tmpMap.put(tmpArrayParam[0], tmpArrayParam[1]);
		}
		String tmpActivityCode = tmpMap.get("activityCode");
		String tmpUserID = tmpMap.get("userID");
		String tmpStrAmount = tmpMap.get("amount");
		String tmpStrLimitTimes = tmpMap.get("limitTimes");
		String tmpStrLimitCycle = tmpMap.get("limitCycle");
		String tmpTimestamp = tmpMap.get("timestamp");
		String tmpKey = tmpMap.get("key");
		if (StringUtils.isBlank(tmpActivityCode)){
			logger.error("签名参数[activityCode]为空！");
			rsp.setFlag(false);
			return rsp;
		}
		if (StringUtils.isBlank(tmpUserID)){
			logger.error("签名参数[userID]为空！");
			rsp.setFlag(false);
			return rsp;
		}
		if (StringUtils.isBlank(tmpStrAmount)){
			logger.error("签名参数[amount]为空！");
			rsp.setFlag(false);
			return rsp;
		}
		int tmpAmount;
		try{
			tmpAmount = Integer.parseInt(tmpStrAmount);
		}catch (Exception e){
			logger.error("签名参数[amount]类必须为int型！");
			rsp.setFlag(false);
			return rsp;
		}
		if (tmpAmount <= 0 || tmpAmount > 20000){
			logger.error("签名参数[amount]已超范围(0,20000]！");
			rsp.setFlag(false);
			return rsp;
		}
		if (StringUtils.isBlank(tmpStrLimitTimes)){
			logger.error("签名参数[limitTimes]为空！");
			rsp.setFlag(false);
			return rsp;
		}
		if (StringUtils.isBlank(tmpStrLimitCycle)){
			logger.error("签名参数[limitCycle]为空！");
			rsp.setFlag(false);
			return rsp;
		}
		int tmpLimitTimes;
		int tmpLimitCycle;
		try{
			tmpLimitTimes = Integer.parseInt(tmpStrLimitTimes);
		}catch (Exception e){
			logger.error("签名参数[limitTimes]类必须为int型！");
			rsp.setFlag(false);
			return rsp;
		}		
		if (tmpLimitTimes < 0 ){
			logger.error("签名参数[limitTimes]必须大于等于0！");
			rsp.setFlag(false);
			return rsp;
		}
		try{
			tmpLimitCycle = Integer.parseInt(tmpStrLimitCycle);
		}catch (Exception e){
			logger.error("签名参数[limitCycle]类必须为int型！");
			rsp.setFlag(false);
			return rsp;
		}		
		if (tmpLimitCycle < 0 ){
			logger.error("签名参数[limitCycle]必须大于等于0！");
			rsp.setFlag(false);
			return rsp;
		}
		if (StringUtils.isBlank(tmpKey)){
			logger.error("签名参数[key]为空！");
			rsp.setFlag(false);
			return rsp;
		}
		if (StringUtils.isBlank(tmpTimestamp)){
			logger.error("签名参数[timestamp]为空！");
			rsp.setFlag(false);
			return rsp;
		}
		if (!tmpKey.equals(tmpQrcodePicSignKey)){
			logger.error("签名参数[key]错误！");
			rsp.setFlag(false);
			return rsp;
		}
		long tmpLong;
		try{
			tmpLong = Long.parseLong(tmpTimestamp);
		}catch (Exception e){
			logger.error("签名参数[timestamp]类必须为long型！");
			rsp.setFlag(false);
			return rsp;
		}
		Long tmpSignEffectiveTime = tmpTWechatConfig.getQrcodePicSignEffectiveTime();
		if (tmpSignEffectiveTime == null || tmpSignEffectiveTime < 0){
			tmpSignEffectiveTime = 0L;
		}
		if (tmpSignEffectiveTime > 0){
			long tmpLongCur = System.currentTimeMillis();
			long tmpDiv = tmpLongCur - tmpLong;
			if (tmpDiv < 0) tmpDiv = - tmpDiv;
			if (tmpDiv > tmpSignEffectiveTime){
				logger.error("签名已过期！");
				rsp.setFlag(false);
				return rsp;
			}
		}
		rsp.setAmount(tmpAmount);
		rsp.setLimitTimes(tmpLimitTimes);
		rsp.setLimitCycle(tmpLimitCycle);
		rsp.setUserID(tmpUserID);
		rsp.setActivityCode(tmpActivityCode);
		return rsp;
	}
	
	private void getWechaturl(String scene, TWechatConfig twechatConfig, TWechatToken twechatToken, QrcodeShowRsp rsp){
		String tmpQrcodeCreateUrl = twechatConfig.getQrcodeCreateUrl() + "?access_token=" + twechatToken.getAccessToken();
		String param = "{\"expire_seconds\": " + twechatConfig.getQrcodeExpire() + ",\"action_name\": \"QR_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": \"" + scene + "\"}}}";
		String resultDesc;
		String rspBody = null;
		try {
			rspBody = HttpUtils.postJson(tmpQrcodeCreateUrl, param);
		} catch (IOException e) {
			resultDesc = "获取二维码失败，二维码生成调用失败！";
			logger.error(resultDesc, e);	
			rsp.setResultCode(WechatResultCode.QRCODE_CREATE_FAIL);
			rsp.setResultDesc(resultDesc);
			return;
		}
		if (StringUtils.isBlank(rspBody)){
			resultDesc = "获取二维码失败，二维码生成失败！";
			logger.error(resultDesc);	
			rsp.setResultCode(WechatResultCode.QRCODE_CREATE_FAIL);
			rsp.setResultDesc(resultDesc);
			return;
		}
		QrcodeCreateRsp tmpQrcodeCreateRsp = (QrcodeCreateRsp) JSONObject.toBean(JSONObject.fromObject(rspBody), QrcodeCreateRsp.class);
		String tmpTicket = tmpQrcodeCreateRsp.getTicket();
		if (StringUtils.isBlank(tmpTicket)){
			resultDesc = "获取二维码失败，二维码生成失败，ticket为空！";
			logger.error(tmpQrcodeCreateRsp.toString());
			logger.error(resultDesc);	
			rsp.setResultCode(WechatResultCode.QRCODE_CREATE_FAIL);
			rsp.setResultDesc(resultDesc);
			return;
		}
		String tmpQrcodeShowUrl = twechatConfig.getQrcodeShowUrl() + "?ticket=" + tmpTicket;
		String fileRelativeDir = "1001" + File.separator + "wechatqrcode";
		String fileName = UUIDUtils.randomUUID() + ".jpg";
		String fileStoreDir = twechatConfig.getQrcodePicStoreDir() + File.separator + fileRelativeDir;
		File file = new File(fileStoreDir);
		if (!file.exists()){
			file.mkdirs();
		}
		String destPath = fileStoreDir + File.separator + fileName;
		try {
			FileUtils.download(tmpQrcodeShowUrl, destPath);
		} catch (Exception e) {
			resultDesc = "获取二维码失败，二维码本地存储失败！";
			logger.error(resultDesc, e);	
			rsp.setResultCode(WechatResultCode.QRCODE_CREATE_FAIL);
			rsp.setResultDesc(resultDesc);
			return;
		}
		String tmpQrcode = fileRelativeDir + File.separator + fileName;
		String httpPath = twechatConfig.getQrcodePicHttpPath() + File.separator + tmpQrcode;
		rsp.setUrl(httpPath);
		rsp.setContent(tmpQrcodeCreateRsp.getUrl());
	}
	
	/**
	 * 已给用户发送红包次数
	 * @param activityCode
	 * @param userID
	 * @param limitCycle
	 * @return
	 * @throws SQLException
	 */
	private int getSendTimes(String activityCode, String userID, int limitCycle) throws SQLException{
		String tmpSql;
		List<Map<String, Object>> tmpListMap;
		if (limitCycle == 0) {//限制每天
			tmpSql = "select count(o.ID) as count from t_wechat_redpack_record o where o.ACCOUNT=? and date_format(o.CREATE_TIME,'%Y-%m-%d')=? and o.ACTIVITY_CODE=?";
			tmpListMap = entityDao.getScrollDataBySql(tmpSql, new Object[]{userID, DateFormatUtil.format(new Date(), "yyyy-MM-dd"), activityCode}, -1, -1);
		} else {//限制活动期间
			tmpSql = "select count(o.ID) as count from t_wechat_redpack_record o where o.ACCOUNT=? and o.ACTIVITY_CODE=?";
			tmpListMap = entityDao.getScrollDataBySql(tmpSql, new Object[]{userID, activityCode}, -1, -1);
		}
		int tmpIntCount = 0;
		if (tmpListMap != null && !tmpListMap.isEmpty()){
			Map<String, Object> tmpMapCount = tmpListMap.get(0);
			BigInteger tmpLongCount = (BigInteger) tmpMapCount.get("count");
			tmpIntCount = tmpLongCount.intValue();
		}
		return tmpIntCount;
	}
	
	@Transactional
	public String handler(String msgType, String event, String eventKey, String toUserName, String fromUserName){
		String rspStr = StringUtils.EMPTY;
		try{
			TWechatConfig tmpTWechatConfig = wechatCache.getWechatConfig();
			if (tmpTWechatConfig == null){
				return rspStr;
			}
			String activityCode;
			String userID;
			int amount;
			int limitTimes = 0;
			int limitCycle = 0;
			String tmpQrcodePicSignKey = tmpTWechatConfig.getQrcodePicSignKey();
			if (StringUtils.isBlank(tmpQrcodePicSignKey)){
				String[] scene = eventKey.split("\\$");
				if (scene == null || scene.length != 5){
					return rspStr;
				}
				activityCode = scene[0];
				userID = scene[1];
				amount = NumberUtils.toInt(scene[2]);
				limitTimes = NumberUtils.toInt(scene[3]);
				limitCycle = NumberUtils.toInt(scene[4]);
			}else{
				CheckSignCustomRsp tmpCheckSignCustomRsp = checkSign(eventKey);
				if (!tmpCheckSignCustomRsp.isFlag()){
					return rspStr;
				}else{
					activityCode = tmpCheckSignCustomRsp.getActivityCode();
					userID = tmpCheckSignCustomRsp.getUserID();
					amount = tmpCheckSignCustomRsp.getAmount();
					limitTimes = tmpCheckSignCustomRsp.getLimitTimes();
					limitCycle = tmpCheckSignCustomRsp.getLimitCycle();
				}
			}
			if (amount <= 0 || amount > 20000){
				return rspStr;
			}
			if (limitTimes < 0){
				return rspStr;
			}
			if (limitCycle < 0){
				return rspStr;
			}
			TextRsp tmpTextRsp = new TextRsp();
			tmpTextRsp.setCreateTime(System.currentTimeMillis());
			tmpTextRsp.setFromUserName(toUserName);
			tmpTextRsp.setToUserName(fromUserName);
			tmpTextRsp.setMsgType(MsgType.TEXT.getType());
			tmpTextRsp.setContent("谢谢参与！");
			try {
				rspStr = XmlUtils.ObjectToXml(tmpTextRsp);
			} catch (JAXBException e) {
				logger.error("对象转xml失败", e);
			}
			if (limitTimes > 0) {
				int tmpIntCount = getSendTimes(activityCode, userID, limitCycle);
				if (tmpIntCount >= limitTimes){
					logger.info(String.format("用户账号[%s]已发红包个数[%s]必须小于等于红包发送限制[%s]", userID, tmpIntCount, limitTimes));
					return rspStr;
				}
			}
			RedpackRsp redpackRsp = wechatManagerService.send(fromUserName, amount, 1);
			logger.info(redpackRsp.toString());
			if (redpackRsp != null && redpackRsp.getReturnCode() != null && redpackRsp.getReturnCode().equals("SUCCESS") &&
					redpackRsp.getResultCode() != null && redpackRsp.getResultCode().equals("SUCCESS")){
				//发送成功
				TWechatRedpackRecord tmpRecord = new TWechatRedpackRecord();
				tmpRecord.setAccount(userID);
				tmpRecord.setAmount(amount);
				tmpRecord.setCreateTime(new Date());
				tmpRecord.setOpenid(fromUserName);
				tmpRecord.setActivityCode(activityCode);
				entityDao.saveVoid(tmpRecord);
				return StringUtils.EMPTY;
			}
		}catch (Exception e){
			logger.error("处理消息失败", e);
		}
		return rspStr;
	}
}

